# coding=utf-8
import sys
import json
import wave
import contextlib
from urllib.parse import urlencode, quote_plus
from urllib.request import urlopen, Request
from urllib.error import URLError
from pygame import mixer
from mutagen.mp3 import MP3

IS_PY3 = sys.version_info.major == 3

API_KEY = "iESMETFIk0VAKyc41UEUybN1"
SECRET_KEY = "Tyh9z1OHSlOr2B8kyUd4TZ74rBD2yG1w"

PER = 4
SPD = 5
PIT = 5
VOL = 5
AUE = 3

FORMATS = {3: "mp3", 4: "pcm", 5: "pcm", 6: "wav"}
FORMAT = FORMATS[AUE]

CUID = "123456PYTHON"

TTS_URL = "http://tsn.baidu.com/text2audio"

class DemoError(Exception):
    pass

TOKEN_URL = "http://aip.baidubce.com/oauth/2.0/token"
SCOPE = "audio_tts_post"

def fetch_token(api_key, secret_key):
    params = {
        "grant_type": "client_credentials",
        "client_id": api_key,
        "client_secret": secret_key,
    }
    post_data = urlencode(params).encode("utf-8") if IS_PY3 else urlencode(params)
    req = Request(TOKEN_URL, post_data)
    try:
        f = urlopen(req, timeout=5)
        result_str = f.read().decode() if IS_PY3 else f.read()
    except URLError as err:
        print("token http response http code : " + str(err.code))
        result_str = err.read().decode() if IS_PY3 else err.read()
    result = json.loads(result_str)
    if "access_token" in result.keys() and "scope" in result.keys():
        if not SCOPE in result["scope"].split(" "):
            raise DemoError("scope is not correct")
        return result["access_token"]
    else:
        raise DemoError("API_KEY or SECRET_KEY可能不正确")

def tts_convert(text, per=PER, spd=SPD, pit=PIT, vol=VOL, aue=AUE, cuid=CUID, api_key=API_KEY, secret_key=SECRET_KEY):
    token = fetch_token(api_key, secret_key)
    tex = quote_plus(text)
    params = {
        "tok": token,
        "tex": tex,
        "per": per,
        "spd": spd,
        "pit": pit,
        "vol": vol,
        "aue": aue,
        "cuid": cuid,
        "lan": "zh",
        "ctp": 1,
    }
    data = urlencode(params).encode("utf-8") if IS_PY3 else urlencode(params)
    req = Request(TTS_URL, data)
    has_error = False
    try:
        f = urlopen(req)
        result_str = f.read()
        headers = {k.lower(): v for k, v in f.headers.items()}
        has_error = "content-type" not in headers or "audio/" not in headers["content-type"]
    except URLError as err:
        print("tts http response http code : " + str(err.code))
        result_str = err.read().decode() if IS_PY3 else err.read()
        has_error = True

    save_file = "error.txt" if has_error else "result." + FORMATS.get(aue, "mp3")
    with open(save_file, "wb") as of:
        of.write(result_str)

    if not has_error:
        if aue == 3:
            audio = MP3(save_file)
            length = audio.info.length
        elif aue == 6:
            with contextlib.closing(wave.open(save_file, 'r')) as f:
                frames = f.getnframes()
                rate = f.getframerate()
                length = frames / float(rate)
        else:
            length = None
        if length:
            print("音频时长为：", length, "秒")
        else:
            print("无法获取音频时长")
        
        # 使用 pygame 播放音频
        mixer.init()
        mixer.music.load(save_file)
        mixer.music.play()
        while mixer.music.get_busy():
            pass
        mixer.music.stop()
    else:
        print("保存文件错误，无法播放。")
    return save_file, length if not has_error else None